library screen_adapter;

import 'dart:async';
import 'dart:collection';
import 'dart:math';
import 'dart:ui' as ui;

import 'package:flutter/material.dart';

part 'screen_adapter_init.dart';

class ScreenAdapter {
  static ScreenAdapter instance = ScreenAdapter._();
  factory ScreenAdapter() => instance;

  ScreenAdapter._();

  static void init({
    Size? designSize,
    required BuildContext context,
  }) {
    if (designSize != null) instance.designSize = designSize;
    instance.context = context;
    instance.data = MediaQuery.of(context);
  }

  Size designSize = const Size(393, 844);
  BuildContext? context;
  MediaQueryData? data;

  static Future<void> ensureScreenSize([
    ui.FlutterView? window,
    Duration duration = const Duration(milliseconds: 10),
  ]) async {
    final binding = WidgetsFlutterBinding.ensureInitialized();
    binding.deferFirstFrame();

    await Future.doWhile(() {
      window ??= binding.platformDispatcher.implicitView;

      if (window == null || window!.physicalSize.isEmpty) {
        return Future.delayed(duration, () => true);
      }

      return false;
    });

    binding.allowFirstFrame();
  }

  double get width => data?.size.width ?? 1;

  double get height => data?.size.height ?? 1;

  double get minScreenLength => min(width, height);

  double get safeTop => data?.viewPadding.top ?? 0;

  double get safeBottom => data?.viewPadding.bottom ?? 0;

  double get designRadius => designSize.width / designSize.height;

  double get deviceRadius => width / height;

  double get scaleWidth => width / designSize.width;

  double get scaleHeight => height / designSize.height;

  double setWidth(num x) => x * scaleWidth;

  double setHeight(num x) => x * scaleHeight;

  double setRadius(num x) => x * min(scaleWidth, scaleHeight);

  double setSp(num x) => x * min(scaleWidth, scaleHeight);
}

extension AdapterEx on num {
  double get w => ScreenAdapter().setWidth(this);

  double get h => ScreenAdapter().setHeight(this);

  double get r => ScreenAdapter().setRadius(this);

  double get sp => ScreenAdapter().setSp(this);

  double get sw => ScreenAdapter().width * this;

  double get sh => ScreenAdapter().height * this;
}
